V předchozí kapitole jsme v místě kliknutí nakreslili barevné kroužky podle určité podmínky. Abychom nakreslili více kroužků, museli jsme kliknout myší vícekrát. To můžeme prozatím vyřešit pomocí smyčky for – nakreslíme více kroužků najednou na náhodném místě.
#############
# 14_1.py #
#############
import tkinter
import random
canvas = tkinter.Canvas()
canvas.pack()
def krouzek():
x = random.randrange(450)
y = random.randrange(320)
if 100<x<150 or 50<y<100:
canvas.create_oval(x-5, y-5, x+5, y+5, fill='green')
else:
canvas.create_oval(x-5, y-5, x+5, y+5, fill='yellow')
for i in range(1, 1000):
krouzek()
canvas.mainloop() #povinné ve VSCode
Smyčku for již můžeme upravit tak, aby se jednotlivé iterace prováděly postupně s určitým časovým zpožděním. K tomu jsme použili canvas.after() a canvas.update(). Takto upravíme smyčku for, aby se vykreslovala postupně.
for i in range(1, 1000):
krouzek()
canvas.update()
canvas.after(10)
Smyčku for používáme v situacích, kdy můžeme předem odhadnout počet opakování. Proto se jí říká cyklus s pevným počtem opakování. Existují však situace, kdy potřebujeme akci opakovat v pravidelných intervalech a přesný počet opakování předem neznáme. K řešení takového problému můžeme použít tzv. časovač, který v pravidelných časových intervalech opakuje zadanou posloupnost příkazů. K tomu slouží příkaz canvas.after(time, function), kterému zadáme nejen čas v milisekundách, ale také název funkce, která se má po pozastavení programu provést.
Náš program po úpravě pomocí časovače:
#############
# 14_2.py #
#############
import tkinter
import random
canvas = tkinter.Canvas(width=450,height=320)
canvas.pack()
def krouzek():
x = random.randrange(450)
y = random.randrange(320)
if 100<x<150 or 50<y<100:
canvas.create_oval(x-5, y-5, x+5, y+5, fill='green')
else:
canvas.create_oval(x-5, y-5, x+5, y+5, fill='yellow')
canvas.after(10, krouzek)
def ctverec():
x = random.randrange(450)
y = random.randrange(320)
if 100<x<150 or 50<y<100:
canvas.create_rectangle(x-5, y-5, x+5, y+5, fill='red')
else:
canvas.create_rectangle(x-5, y-5, x+5, y+5, fill='blue')
canvas.after(30, ctverec)
ctverec()
krouzek()
canvas.mainloop() #povinné ve VSCode
Program po nějaké době vykreslí takový obrázek:
Následující program postupně nakreslí několik kuliček.
#############
# 14_3.py #
#############
import tkinter
canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()
def micek():
global x
global y
canvas.create_oval(x-5, y-5, x+5, y+5)
y = y+5
if y<200:
canvas.after(100, micek)
x = 200
y = 5
micek()
canvas.mainloop() #povinné ve VSCode
Všimněte si, že jsme v programu nastavili proměnnou x na 200 a y na 5. V těchto proměnných jsou souřadnice, na kterých je nakreslena první kulička. Po nastavení proměnných spustíme funkci micek. Tato funkce nakreslí kuličku (kruh) na souřadnice podle hodnot proměnných x a y. Další kuličku chceme nakreslit na souřadnice, které jsou uvedeny v proměnných x a y. Další chceme nakreslit o 5 bodů níže. Proto zvýšíme y o 5, takže napíšeme y = y + 5. Protože jsme ve funkci micek, nemůžeme zde normálně měnit hodnotu proměnné, která se používá v hlavním programu mimo naši funkci. Jak y, tak x jsou globální proměnné, nikoli lokální proměnné ve funkci, kde je chceme změnit. V takových situaci musíme použít příkaz global a název proměnné, abychom funkci sdělili, že chceme pracovat s proměnnou globální proměnná. Nyní má y hodnotu 10. V dalším řádku se ptáme, zda je y menší než 200, a to pouze v případě, že je tato podmínka splněna, naplánujeme další provedení funkce micek na 100 milisekund. Vidíme, že jsme vytvořili časovač, který neopakuje příkazy donekonečna, ale jen tak dlouho, dokud je splněna podmínka. Po spuštění programu uvidíme, že se pod sebou vykresluje několik kuliček.
Pomocí canvas.delete('all') můžeme odstranit vše, co jsme nakreslili. Pokud tento příkaz napíšeme na začátku funkce, funkce pokaždé vymaže vše nakreslené a my uvidíme pouze poslední nakreslený objekt. To je princip animace. Nejprve vymažeme původní obrázky a nakreslíme stejný tvar postupně v posunuté poloze.
def micek():
global x
global y
canvas.delete('all')
canvas.create_oval(x-5, y-5, x+5, y+5)
y = y+5
if y<200:
canvas.after(100, micek)
Co tento program udělá, když obrátíme pořadí create_oval a delete?
Na které souřadnici bude nakreslen poslední obrazec?
Co udělá tento program, pokud nahradíme podmínku touto y == 200?
Co program udělá, jestliže zvětšíme y o 6 (y = y + 6) a nahradíme podmínku následující: y == 200?
Vytvořte program 14_vodorovne.py, který přesune kuličku vodorovně od levého okraje k pravému okraji.
Vytvořte program 14_sikmo.py, ve kterém se bude kulička pohybovat šikmo dolů.
Vytvořte program 14_nahoru_dolu.py, ve kterém bude kulička padat svisle shora dolů. Po dosažení spodní hrany se její pohyb obrátí – bude se posouvat opět nahoru. Takto stále dokola.
Odhadněte, co udělá následující program:
#############
# 14_4.py #
#############
import tkinter
canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()
def micek():
global x
global y
global pokracovat
canvas.delete('all')
canvas.create_oval(x-5, y-5, x+5, y+5)
y = y + 5
if y > 250:
y = 5
if pokracovat == 1:
canvas.after(100, micek)
def stop(souradnice):
global pokracovat
pokracovat = 0
pokracovat = 1
x = 200
y = 5
micek()
canvas.bind('<ButtonPress-1>', stop)
canvas.mainloop() #povinné ve VSCode
Odhadněte, co udělá následující program:
#############
# 14_5.py #
#############
import tkinter
canvas = tkinter.Canvas(width=400,height=300)
canvas.pack()
def micek():
global x
global y
global pokracovat
canvas.delete('all')
canvas.create_oval(x-5, y-5, x+5, y+5)
y = y + 5
if y > 250:
y = 5
if pokracovat == 1:
canvas.after(100, micek)
def stop(souradnice):
global pokracovat
if pokracovat == 1:
pokracovat = 0
else:
pokracovat = 1
micek()
pokracovat = 1
x = 200
y = 5
micek()
canvas.bind('<ButtonPress-1>', stop)
canvas.mainloop() #povinné ve VSCode
Vytvořte program 14_jednicky_nuly.py, který bude postupně zapisovat na plátno 0 nebo 1 (náhodně vybrané):
Program bude mít následující vlastnosti:
Vytvořte program 14_kolize.py , který má následující vlastnosti:
Vytvořte program 14_dostihy.py simulující dostihový závod, který má následující vlastnosti: